#ifndef __REDUZE_H__
#define __REDUZE_H__
#include <bubblesii/pfrac.hpp>
#include "misc.h"
#include "graph.h"
#include "utils.h"
#include "symconst.h"
#include "topology.h"
#include "projector.h"
scalar_products reduze_sp();
lst get_sp_lst();

lst props(ex);
expair get_num_prop_part(ex);
ex get_no_prop_part(ex);
ex get_prop_part(ex);
void mincer(Graph,dia_ext_legs);
void reduze(Graph&);
void reduze_ng(Graph&);
void bubble(Graph&);
exmap subs_1_map(lst);
//scalar_products sp_from_ex(ex);

class  sp_from_ex_functor
{
  lst sp_symbols_lst;
 public:
  lst get_sp_symbols_lst()
  {
    return sp_symbols_lst;
  }
  scalar_products operator()(const ex& in_ex)
  {
    //  std::set<symbol> 
    exset sym_set;
    for(const_preorder_iterator it = in_ex.preorder_begin();it!=in_ex.preorder_end();++it)
      {
        if(is_a<indexed>(*it))
          {
            ex ind_ex = *it;
          
            exmap repls;
            ind_ex.match(indexed(wild(),ind_ex.get_free_indices()),repls);
            cout<< "finding in "<< ind_ex<<" found "<<repls<<endl;
            ind_ex = wild().subs(repls);
            for(const_preorder_iterator s_it = ind_ex.preorder_begin();s_it!=ind_ex.preorder_end();++s_it)
              if(is_a<symbol>(*s_it))
                {
                  cout<<"   "<<(*s_it)<<endl;
                  sym_set.insert(ex_to<symbol>(*s_it));
                }
          }
      }
    cout<<sym_set<<endl;
    scalar_products sp;
    BOOST_FOREACH(ex sp_sym1,sym_set)
      {
        BOOST_FOREACH(ex sp_sym2,sym_set)
          {
            string str = ("(");
            ex sp_ex = get_symbol(str+ex_to<symbol>(sp_sym1).get_name()+"."+ex_to<symbol>(sp_sym2).get_name()+")");
            sp_symbols_lst.append(sp_ex);
            sp.add(sp_sym1,sp_sym2,sp_ex);
          }
      }
    return sp;
  }
};

struct bubblesii_prop_to_idx_prop : public map_function
{
  sp_from_ex_functor sp_from_ex;
 bubblesii_prop_to_idx_prop(sp_from_ex_functor spin): sp_from_ex(spin)
    {
    }
  ex operator()(const ex& e)
  {
    //    varidx dummy_idx(symbol("idx"),4); 
    symbol idx_dummy("idx");
    if(is_a<bubblesii::prop>(e))
      {
        ex tmp_ex = indexed(ex_to<bubblesii::prop>(e).op(2),varidx(idx_dummy,cnst::D-2*cnst::C*cnst::eps)) *  indexed(ex_to<bubblesii::prop>(e).op(2),varidx(idx_dummy,4).toggle_variance());
        ex px_tmp2 = tmp_ex;
        tmp_ex = tmp_ex.expand(expand_options::expand_indexed).simplify_indexed(sp_from_ex(px_tmp2));
        cout<<"map_tmp :  "<<tmp_ex<<endl;
        return 1/pow(tmp_ex - pow(ex_to<bubblesii::prop>(e).op(0),2),ex_to<bubblesii::prop>(e).op(1));
      }
    else return e.map(*this);
  }
};
#endif
